package 操作.工具类

import io.ktor.util.encodeBase64
import kotlinx.datetime.Clock
import kotlinx.datetime.Instant
import kotlinx.datetime.LocalDate
import kotlinx.datetime.LocalDateTime
import kotlinx.datetime.LocalTime
import kotlinx.datetime.TimeZone
import kotlinx.datetime.toLocalDateTime
import okio.ByteString.Companion.encodeUtf8
import java.util.regex.Pattern
import kotlin.math.abs

object 文本操作{
    fun 正则中文起始符() : Int = '\u4e00'.code
    fun 正则中文结束符() : Int = '\u9fa5'.code


    fun 时间到文本(date : LocalDate,time : LocalTime,pattern: String = "yyyy-MM-dd HH:mm:ss") : String{
        return pattern.replace("yyyy",date.year.toString())
            .replace("MM",date.monthNumber.toString().let {
                if (it.length == 1) "0$it"
                else it
            })
            .replace("dd",date.dayOfMonth.toString().let {
                if (it.length == 1) "0$it"
                else it
            })
            .replace("HH",time.hour.toString().let {
                if (it.length == 1) "0$it"
                else it
            })
            .replace("mm",time.minute.toString().let {
                if (it.length == 1) "0$it"
                else it
            })
            .replace("ss",time.second.toString().let {
                if (it.length == 1) "0$it"
                else it
            })
    }

    fun 时间到文本(t : LocalDateTime, pattern : String = "yyyy-MM-dd HH:mm:ss") : String{
        return pattern.replace("yyyy",t.year.toString())
            .replace("MM",t.monthNumber.toString().let {
                if (it.length == 1) "0$it"
                else it
            })
            .replace("dd",t.dayOfMonth.toString().let {
                if (it.length == 1) "0$it"
                else it
            })
            .replace("HH",t.hour.toString().let {
                if (it.length == 1) "0$it"
                else it
            })
            .replace("mm",t.minute.toString().let {
                if (it.length == 1) "0$it"
                else it
            })
            .replace("ss",t.second.toString().let {
                if (it.length == 1) "0$it"
                else it
            })
    }

    fun 时间秒到时分(sender : Int) : String{
        val f = (abs(sender) / 60).toString().let {
            if (it.length == 1) "0$it"
            else it
        }
        val m = (abs(sender) % 60).toString().let {
            if (it.length == 1) "0$it"
            else it
        }
        return if (sender < 0) "- $f:$m" else "$f:$m"
    }

    /**
     * @param time 时间戳
     * @param pattern 返回日期类型 yyyy-MM-dd HH:mm:ss  年费-月份-日  时:分:秒   注意月份为大写MM
     */
    fun 时间戳到文本(time : Long, pattern : String = "yyyy-MM-dd HH:mm:ss") : String{
        var milSecond = time
        if (milSecond.toString().length <= 10) {
            milSecond *= 1000
        }

        val t =  Instant.fromEpochMilliseconds(milSecond).toLocalDateTime(TimeZone.UTC)
        return pattern.replace("yyyy",t.year.toString())
            .replace("MM",t.monthNumber.toString().let {
                if (it.length == 1) "0$it"
                else it
            })
            .replace("dd",t.dayOfMonth.toString().let {
                if (it.length == 1) "0$it"
                else it
            })
            .replace("HH",t.hour.toString().let {
                if (it.length == 1) "0$it"
                else it
            })
            .replace("mm",t.minute.toString().let {
                if (it.length == 1) "0$it"
                else it
            })
            .replace("ss",t.second.toString().let {
                if (it.length == 1) "0$it"
                else it
            })
    }



    fun 生成分秒文本(秒 : Int) : String{
        val f = (秒 / 60).toString().let {
            if (it.length == 1) "0$it"
            else it
        }

        val m = (秒 % 60).toString().let {
            if (it.length == 1) "0$it"
            else it
        }

        return "$f:$m"
    }


    /**
     * 取地址前缀
     * http://a.nr.cn/xxx  返回  http
     */
    fun 取地址前缀(url: String?): String {
        if (url.isNullOrEmpty()) return ""
        val t = url.left(":") ?: return ""
        return if (t.contains("/") || t.contains("?")
            || t.contains("=") || t.contains(".")) {
            ""
        } else t
    }

    /**
     * 取地址文件后缀，不含小数点。  xxx/a/b.jpg -> jpg
     */
    fun 取地址文件后缀(_url: String) : String{
        if (_url.isEmpty()) return ""
        var url = _url

        // 判断是否有问号
        url = url.left2("?") ?: url

        if (url.isEmpty()) return ""
        return url.right(".") ?: ""
    }

    /**
     * 取地址文件名 xxx/a/b.jpg -> b.jpg
     */
    fun 取地址文件名(url:String) : String{
        var r = url
        if (r.endsWith("/")) r = r.substring(0,r.length - 1)
        return (r.left("?")?:r).right2("/") ?:""
    }
    fun 取地址文件名不含后缀(url:String) : String{
        return (url.left("?")?:url).right2("/").let {
            it?.left(".") ?: it ?: ""
        }
    }

    /**
     * 从地址中获取主机地址， 如  http://a.nr.cn/xxx  返回  nr.cn
     */
    fun 取地址主机(url: String): String {

        if (url.isEmpty()) return ""

        var host : String= url

        // 去前缀  http://a.nr.cn/xxx -> a.nr.cn/xxx
        host = host.right("://") ?: host

        // 去域名后部   a.nr.cn/xx  ->  a.nr.cn
        host = host.left("/") ?: host

        // 去端口  a.nr.cn:8080 -> a.nr.cn
        host = host.left(":") ?: host

        return host
    }


    /**
     * 从地址中获取主机地址， 如  http://a.nr.cn/xxx  返回  a.nr.cn
     */
    fun 取地址域名(url: String): String {

        // 先取地址  http://a.nr.cn/xxx -> a.nr.cn
        var host = 取地址主机(url)

        // 只要后两个值    [a].[nr].[cn]
        host.split(".").let {
            if (it.size > 2){
                host = "${it[it.size - 2]}.${it[it.size - 1]}"
            }
        }
        return host
    }

    /**
     * 获取地址、路径的绝对路径
     * 检测URL 是否带 域名  没有则从  判断URL中获取
     * @param url1 需要检测的相对或绝对url
     * @param url2  进行比对的url ，此URL应当含有绝对路径
     * @return
     */
    fun 取绝对地址(url1: String, _url2: String?=null): String {
        // 原生
        if (url1.startsWith("m:") || url1.startsWith("#")) return url1

        // 没有匹配值
        if (url1.isEmpty()) return url1

        // 添加协议头
        if (_url2.isNullOrEmpty()){
            if (url1.startsWith("//")) {
                return "http:$url1"
            }
            url1.left("://").let {
                if (it == null || it.contains(".")) return "http://$url1"
            }
        }

        // 拥有完整的地址也不用管
        url1.left("://")?.let {
            if (it.contains(Regex("[\\u4e00-\\u9fa5A-Za-z_]+[\\u4e00-\\u9fa5A-Za-z0-9_]"))) return url1
        }


        var url2 = _url2!!


        // hosturl 必须带前缀
        if (取地址前缀(url2).isEmpty()) {
            url2 = "http://$url2"
        }

        // 双斜杠：缺少http头   ...   //xx.com -> http://xxx.com
        if (url1.startsWith("//")) {
            return 取绝对地址2(url2.left("//") + url1) // 从判断URL中引入 HTTP  毕竟有可能为 https 有些网站不支持跳转
        }

        // 单斜杆：缺少服务器地址 ...  /index.html -> http://xx.com/index.html
        else if (url1.startsWith("/")) {

            val left = url2.left(9,"/") ?: url2
            return 取绝对地址2(left + url1)
        }

        // ./ 从当前目录开始
        else if (url1.startsWith("./")){
            val dir = url2.left2("/") ?: return url1
            if (!dir.contains(".")) return url1 // 可能返回的是协议头中的斜杠  那就是条件不达成
            return 取绝对地址2(dir + "/" + url1.substring(2))
        }

        // ../ 从上级目录开始
        else if (url1.startsWith("../")){

            var dir = url2.left2("/") ?: return url1
            dir = dir.right2("/") ?: return url1
            if (!dir.contains(".")) return url1 // 可能返回的是协议头中的斜杠  那就是条件不达成
            return 取绝对地址2(dir+"/" + url1.substring(3))
        }

        // 不带符号，从当前目录开始
        else{
            val dir = url2.left2("/") ?: return url1
            if (!dir.contains(".")) return url1 // 可能返回的是协议头中的斜杠  那就是条件不达成
            return 取绝对地址2("$dir/$url1")
        }
    }
    private fun 取绝对地址2(str : String) : String = str.replace("\\/","/")


    /**
     * 判断key 是否合法(不含特殊字符)
     */
    fun 名称是否合法(key : String) : Boolean{
        // 正则表达式说明：
        // \p{L} 匹配所有 Unicode 字母
        // \p{N} 匹配所有 Unicode 数字
        // _ 匹配下划线
        // + 表示匹配一个或多个合法字符
        // ^ 和 $ 确保字符串完全匹配
        val regex = "^[\\p{L}\\p{N}_]+$".toRegex()
        return regex.matches(key)
    }


    fun 全角符号转半角(str : String) : String{
        return str.replace('，', ',')
            .replace('。', '.')
            .replace('：', ':')
            .replace('；', ';')
            .replace('“', '"')
            .replace('”', '"')
    }


    /**
     * 正则匹配
     * @param text 要匹配的内容
     * @param reg 正则
     */
    fun 正则匹配(text: String, reg: String): Boolean {
        if (text == reg) return true
        try {
            return if (text.isEmpty() || reg.isEmpty()) false
            else {
                val matcher = Pattern
                    .compile(reg, Pattern.CASE_INSENSITIVE)
                    .matcher(text)
                return matcher.find()
            }
        }catch (ex : java.lang.Exception){
            ex.printStackTrace()
            return false
        }
    }

    // 正则匹配返回首个 [子]表达式文本
    fun 取文本(text: String, reg: String): String? {
        return try {
            val pattern = Pattern.compile(reg)
            val matcher = pattern.matcher(text)
            while (matcher.find()) {
                if (matcher.groupCount() > 0) {
                    return matcher.group(1)
                }
            }
            null
        } catch (ex: Exception) {
            ex.printStackTrace()
            return null
        }
    }


}


fun String.去转义符() : String{
    if (this.isEmpty()) return this
    val strs = StringBuilder()
    var endx = 0 // 上次截取的位置
    var pos = this.indexOf("\\",0)
    while (pos != -1){
        // 先截取
        strs.append(this.substring(endx,pos))
        endx = pos // 记录截取位置


        // 转义符下一个值
        try {
            when(this[pos + 1]){
                '"' -> strs.append("\"")
                '\'' -> strs.append("\'")
                '\\' -> strs.append("\\")
                '/' -> strs.append("/") // 沙币JSON 转义这个字符搞屁吃  操。
                'n' -> strs.append("\n")
                'r' -> strs.append("\r")
                't' -> strs.append("\t")
                'b' -> strs.append("\b")
                else -> {
                    // throw ParserException("非法转义符 ${a[pos + 1]}",pos)
                    pos = this.indexOf("\\",pos+1) // 不管他 跳过就是
                    continue
                }
            }
            endx = pos + 2 // 上面都是两字符转解码并接入到 strs 中
            pos = this.indexOf("\\",endx)
        }
        catch (e : IndexOutOfBoundsException){
            // 无视
            //e.printStackTrace()
            pos = -1
        }


    }

    // 剩余的
    strs.append(this.substring(endx))
    return strs.toString()
}
fun String.转义() : String{
    val strs = StringBuilder()
    this.forEach {
        when (it.code){
            // \n
            10 -> strs.append("\\n")
            13 -> strs.append("\\r")
            34 -> strs.append("\\\"") // 双引号
            39 -> strs.append("\\\'")  // 单引号 '
            92 -> strs.append("\\\\") // 转义符
            else -> strs.append(it)
        }
    }
    return strs.toString()
}

/**
 * 分割但忽略含转义符的key
 */
fun String.split2Escape(key : String) : List<String>{
    val ls = ArrayList<String>()
    var index = this.indexOfEscape(key)
    var end = 0

    while (index != -1){
        ls.add(this.substring(end,index))
        end = index + key.length
        index = this.indexOfEscape(key,end)
    }

    if (end < this.length) {
        ls.add(this.substring(end))
    }

    return ls
}

/**
 * 寻找下一个没有非转义的KEY.
 * 如  "a\bcba".indexOfEscape("b") 会返回c后面的b，而 indexOf("b") 返回 斜杠(转义符)后面的b索引
 * @param fromIndex 起始位置
 */
fun String.indexOfEscape(key : String,fromIndex : Int = 0) : Int{
    var i = this.indexOf(key, fromIndex)
    while (i != -1) {
        // 排除转义

        if (this.isEscape(i)) {
            i = this.indexOf(key, i + key.length)
            continue
        }
        // 取闭合
        return i
    }
    return -1
}
fun String.replaceOfEscape(old : String,new : String) : String{
    val news = StringBuilder()
    var end = 0
    var i = this.indexOfEscape(old, end)
    while (i != -1){
        news.append(this.substring(end,i))
            .append(new)

        end = i + old.length // 跳过old key
        i = this.indexOfEscape(old, end)
    }
    news.append(this.substring(end))
    return news.toString()
}

/**
 * 判断指定位置的key是否为转义值 是否转义 \
 * @return
 */
fun String.isEscape(index: Int): Boolean {

    // 跳到上一个字符
    var i = index - 1
    if (i < 0) return false

    // 匹配前面所有 转义字符
    var zySize = 0 // 转义字符数量
    var word = this.substring(i, i + 1)
    while (word == "\\") {
        zySize++
        i--
        word = if (i >= 0) this.substring(i, i + 1) else ""
    }

    // 如果转义字符数量为单数，就是转义，否则前面的全是 \
    return zySize % 2 == 1
}

fun String.正则匹配(reg: String): String? {
    return try {
        val matchResult = reg.toRegex().find(this)
        matchResult?.groupValues?.get(1)
    } catch (ex: Exception) {
        ex.printStackTrace()
        null
    }
}


/**
 * base64编码
 */
fun String.encodeBase64(): String {
    val byteArray = this.chunked(2).map { it.toInt(radix = 16).toByte() }.toByteArray()
    return byteArray.encodeBase64()
}

fun String.md5(): String {
    return this.encodeUtf8().md5().hex()
}
fun String.md5(vararg d : Any) : String{
    var k = this.md5()
    d.forEach {
        k += it.toString().md5()
    }
    return k.md5()
}
fun String.md5ntime() : String{
    return (this + Clock.System.now().toEpochMilliseconds()).md5()
}
// 取文本左右值，xx2为从右边开始读
fun String.left(t1: String): String? {
    val ri: Int
    ri = this.indexOf(t1)
    return if (ri < 1) null else this.substring(0, ri)
}
// 取指定长度，未达到的
fun String.left(lenght : Int) : String{
    return if (this.length < lenght) return this.substring(0,lenght)
    else this
}

/**
 * @param 多一个起始位置
 */
fun String.left(start: Int, end: String): String? {
    return try {
        val i = this.indexOf(end, start)
        if (i == 0) null
        else this.substring(0, i)
    } catch (ex: Exception) {
        null
    }
}
fun String.right(t1 : String) : String?{
    val ri = this.indexOf(t1)
    return if (ri == -1) null else this.substring(ri + t1.length)
}
fun String.left2(t1: String?): String? {
    if (t1.isNullOrEmpty()) return null
    val ri: Int = this.lastIndexOf(t1)
    return if (ri < 1) null else this.substring(0, ri)
}
// 从后面开始找指定词
fun String.right2(t1: String?): String? {
    if (t1.isNullOrEmpty()) return ""
    val ri = this.lastIndexOf(t1)
    return if (ri == -1) null else this.substring(ri + t1.length)
}

/**
 * @param start 开始位置
 * @param end 结束字符，从左往右
 */
fun String.center(start: Int, end: String): String? {
    return try {
        val i = this.indexOf(end, start)
        if (i == 0) null
        else this.substring(0, i)
    } catch (ex: Exception) {
        null
    }
}
fun String.center(left: String, right: String): String? {
    if (this.isEmpty() || left.isEmpty() || right.isEmpty()) {
        return null
    }
    var let = this.indexOf(left)
    if (let == -1) return null
    let += left.length
    val rit = this.indexOf(right, let)
    return if (rit == -1) null else this.substring(let, rit)
}
